package com.myzhouye.biz.service;/***
 *                    _ooOoo_
 *                   o8888888o
 *                   88" . "88
 *                   (| -_- |)
 *                    O\ = /O
 *                ____/`---'\____
 *              .   ' \\| |// `.
 *               / \\||| : |||// \
 *             / _||||| -:- |||||- \
 *               | | \\\ - /// | |
 *             | \_| ''\---/'' | |
 *              \ .-\__ `-` ___/-. /
 *           ___`. .' /--.--\ `. . __
 *        ."" '< `.___\_<|>_/___.' >'"".
 *       | | : `- \`.;`\ _ /`;.`/ - ` : | |
 *         \ \ `-. \_ __\ /__ _/ .-` / /
 * ======`-.____`-.___\_____/___.-`____.-'======
 *                    `=---='
 *
 * .............................................
 *          佛祖保佑             永无BUG
 */

import com.myzhouye.biz.dto.BaseFactory;
import com.myzhouye.biz.model.FactoryTemplate;
import com.myzhouye.biz.model.UserFactoryEntity;
import com.myzhouye.biz.repository.FactoryTemplateRepository;
import com.myzhouye.biz.repository.UserFactoryRepository;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;

/**
 * @program: demo1
 * @description:
 * @author: 那条蠢鱼
 * @create: 2025-09-29 11:20
 **/
@Getter
@Slf4j
@Service
@RequiredArgsConstructor
public class BaseFactoryService  {
    private final Map<String, BaseFactory> factories = new ConcurrentHashMap<>();
    private final WarehouseService warehouseService;
    private final FactoryTemplateRepository factoryTemplateRepository;
    private final UserFactoryRepository userFactoryRepository;
    private final Map<Long, Map<String, BaseFactory>> userFactories = new ConcurrentHashMap<>();
    // 2. 添加Redis缓存支持
    private final ReactiveRedisTemplate<String, Object> reactiveRedisTemplate;
    private static final String USER_FACTORIES_KEY = "user:%s:factories";
    private final RedisFactoryCacheService redisFactoryCacheService;

    /*@PostConstruct
    public void init() {
        // Example of initializing a factory
        createFactory("1", "Factory 1", 100, "Product A");
    }*/

    public String createFactory(String name, int warehouseSize, String productName, int productionSpeed,Long userId) {
        String id = UUID.randomUUID().toString();
        // 创建工厂实例时直接指定生产速度(周期间隔)
        BaseFactory factory = new BaseFactory(id, name, warehouseSize, productName, productionSpeed,userId,redisFactoryCacheService);
        // 内存存储(保证任务调度正常运行)
        userFactories.computeIfAbsent(userId, k -> new ConcurrentHashMap<>())
                .put(id, factory);

        // Redis持久化(用于数据备份和重启恢复)
        saveFactoryToRedis(userId, factory);
        factories.put(id, factory);
        factory.start(); // 启动周期性任务
        return id;
    }

    // 4. 添加Redis持久化方法
    private void saveFactoryToRedis(Long userId, BaseFactory factory) {
        String key = String.format(USER_FACTORIES_KEY, userId);
        reactiveRedisTemplate.opsForHash()
                .put(key, factory.getId(), factory);
    }

    // 5. 系统启动时从Redis恢复工厂数据
    @PostConstruct
    public void init() {
        // 从Redis加载所有用户工厂到内存
        reactiveRedisTemplate.keys(USER_FACTORIES_KEY.replace("%s", "*"))
                .flatMap(key -> {
                    Long userId = Long.parseLong(key.split(":")[1]);
                    return reactiveRedisTemplate.opsForHash().values(key)
                            .cast(BaseFactory.class)
                            .doOnNext(factory -> {
                                userFactories.computeIfAbsent(userId, k -> new ConcurrentHashMap<>())
                                        .put(factory.getId(), factory);
                                factory.start(); // 恢复任务调度
                            });
                })
                .subscribe();
    }

    public String createFactoryByTemplate(String id,Long userId) {
        FactoryTemplate factoryTemplate = factoryTemplateRepository.findById(Long.parseLong(id))
                .orElseThrow(() -> new IllegalArgumentException("工厂模板id不存在"));

        String factoryId = UUID.randomUUID().toString();
        String factoryName = factoryTemplate.getTemplateName() + "#" + generateRandomCode(6);

        // 使用新的构造函数
        BaseFactory factory = new BaseFactory(
                factoryId,
                factoryName,
                factoryTemplate.getWarehouseSize(),
                factoryTemplate.getProduct().getName(),
                factoryTemplate.getProductionSpeed(),
                userId,
                redisFactoryCacheService
        );

        // 内存存储(保证任务调度正常运行)
        userFactories.computeIfAbsent(userId, k -> new ConcurrentHashMap<>())
                .put(id, factory);

        // Redis持久化(用于数据备份和重启恢复)
        saveFactoryToRedis(userId, factory);
        factories.put(factoryId, factory);
        factory.setAcceleration(factoryTemplate.getAcceleration()); // 设置加速系数
        factory.start(); // 启动周期性任务
        return factoryId;
    }

    /**
     * 生成随机6位大写字母与数字编号
     * @param i 编号长度
     * @return 随机编号
     */
    private String generateRandomCode(int i) {
        return RandomStringUtils.randomAlphanumeric(i).toUpperCase();
    }


    public int getResourceCount(String id) {
        BaseFactory factory = factories.get(id);
        if (factory != null) {
            return factory.getProductNums();
        }
        return 0;
    }

    public int consumeResources(String id, int count) {
        BaseFactory factory = factories.get(id);
        if (factory != null) {
            int currentProductNums = factory.getProductNums();
            //不足的时候返回-1，不进行扣减
            if (count > currentProductNums) {
                return -1;
            }
            factory.decrementProduct(count);
            //返回剩余数量
            return factory.getProductNums();
        }
        return -1;
    }

    public int collectToWarehouse(String id) {
        BaseFactory factory = factories.get(id);
        if (factory != null) {
            //判断仓库剩余容量，尽可能多的收集
            Integer freeSpace = warehouseService.getWarehouse().getFreeSpace();
            //如果没有仓库，返回-1
            if(freeSpace==-1) {
                return -1;
            }
            //如果仓库没有空间，返回-2
            if(freeSpace==0) {
                return -2;
            }
            int currentProductNums = factory.getProductNums();
            int collectCount = Math.min(currentProductNums, freeSpace);
            factory.decrementProduct(collectCount);
            //添加到仓库
            warehouseService.append(factory.getProductName(),collectCount);

            //返回收集数量
            return collectCount;
        }else{
            //工厂不存在，返回-3
            return -3;
        }

    }

    /**
     * 系统关闭前执行 - 同步内存数据到Redis和数据库
     */
    @PreDestroy
    public void preDestroy() {
        log.info("开始执行系统关闭前数据同步...");
        long startTime = System.currentTimeMillis();

        // 1. 同步工厂数据到Redis并持久化到数据库
        syncFactoriesToStorage();

        // 2. 同步仓库数据到Redis并持久化到数据库
        syncWarehousesToStorage();

        log.info("数据同步完成，耗时: {}ms", System.currentTimeMillis() - startTime);
    }

    /**
     * 同步工厂数据到Redis和数据库
     */
    private void syncFactoriesToStorage() {
        CountDownLatch latch = new CountDownLatch(userFactories.size());

        userFactories.forEach((userId, factoryMap) -> {
            // 1. 同步内存工厂到Redis
            factoryMap.values().forEach(factory -> {
                redisFactoryCacheService.cacheUserFactory(userId, factory).block();
            });

            // 2. 批量保存到数据库
            List<UserFactoryEntity> entities = factoryMap.values().stream()
                    .map(factory -> convertToEntity(userId, factory))
                    .toList();

            userFactoryRepository.saveAll(entities);
            latch.countDown();
        });

        try {
            latch.await(); // 等待所有用户数据处理完成
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("工厂数据同步被中断", e);
        }
    }

    /**
     * 同步仓库数据到Redis和数据库
     */
    private void syncWarehousesToStorage() {
        // 实现类似工厂的仓库数据同步逻辑
        // ...
    }

    /**
     * 转换BaseFactory为数据库实体
     */
    private UserFactoryEntity convertToEntity(Long userId, BaseFactory factory) {
        UserFactoryEntity entity = new UserFactoryEntity();
        entity.setUserId(userId);
        entity.setName(factory.getName());
        entity.setProductName(factory.getProductName());
        entity.setWarehouseSize(factory.getWarehouseSize());
        entity.setProductNums(factory.getProductNums());
        entity.setProductionSpeed(factory.getIntervalSeconds());
        entity.setAcceleration(factory.getAcceleration());
        return entity;
    }

}
